#pragma once

#include <iostream>
#include <memory>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <signal.h>
#include <functional>
#include "Common.hpp"
#include "Log.hpp"
#include "InetAddr.hpp"

using namespace LogModule;

using func_t=std::function<std::string(const std::string&,InetAddr)>;
const int defaultfd=-1;
//禁止拷贝构造和赋值重载
class tcpserver : public NoCopy
{
public:
    tcpserver(uint16_t port,func_t func)
    :_port(port),
    _listensockfd(defaultfd),
    _isrunning(false),
    _func(func)
    {}
    ~tcpserver()
    {}
    void init()
    {
        //1，创建套接字
        _listensockfd=socket(AF_INET,SOCK_STREAM,0);
        if(_listensockfd<0)
        {
            //打印日志信息
            LOG(LogLevel::FATAL)<<"创建套接字失败";
            exit(SOCKET_ERR);
        }
        LOG(LogLevel::INFO)<<"创建套接字成功"<<_listensockfd;

        //2，绑定ip和端口号
        InetAddr addr(_port);//只需传入端口号即可，这里 调用的构造函数会将IP设置为0，也就是INADDR_ANY
        int n=bind(_listensockfd,addr.NetAddrPtr(),addr.NetAddrLen());
        if(n<0)
        {
            LOG(LogLevel::FATAL)<<"绑定失败";
            exit(BIND_ERR);
        }
        LOG(LogLevel::FATAL)<<"绑定成功";

        //3，listen状态，监听连接
        n=listen(_listensockfd,8);
        if(n<0)
        {
            LOG(LogLevel::FATAL)<<"监听失败";
            exit(LISTEN_ERR);
        }
        LOG(LogLevel::FATAL)<<"监听成功";
    }
    void service(int sockfd,InetAddr addr)
    {
        char buffer[1024];//定义缓冲区
        while(true)
        {
            //读取数据
            ssize_t n=read(sockfd,buffer,sizeof(buffer)-1);
            //n>0读取成功
            //n<0读取失败
            //n==0对端关闭连接，读取到了文件的末尾
            if(n>0)
            {
                buffer[n]=0;
                //查看是哪个主机的哪个进程发送的消息，在服务端回显
                LOG(LogLevel::DEBUG)<<addr.StringAddr()<<" #"<<buffer;

                //写回数据
                std::string echo_string="echo #";
                echo_string+=buffer;

                //写回给客户端
                write(sockfd,echo_string.c_str(),echo_string.size());
            }
            else if (n == 0)
            {
                LOG(LogLevel::DEBUG) << addr.StringAddr() << " 退出了...";
                close(sockfd);
                break;
            }
            else
            {
                LOG(LogLevel::DEBUG) << addr.StringAddr() << " 异常...";
                close(sockfd);
                break;
            }
        }
    }
    class ThreadData
    {
    public:
        ThreadData(int fd, InetAddr &ar, tcpserver *s) : sockfd(fd), addr(ar), tsvr(s)
        {
        }

    public:
        int sockfd;
        InetAddr addr;
        tcpserver *tsvr;
    };
    //新线程的入口函数
    static void *Routine(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData *>(args);
        td->tsvr->service(td->sockfd, td->addr);
        delete td;
        return nullptr;
    }

    void run()
    {
        _isrunning=true;
        while(_isrunning)
        {
            //4，获取连接
            struct sockaddr_in peer;
            socklen_t len=sizeof(sockaddr_in);
            //如果没有连接，accept就会阻塞
            //sockfd提供接下来的read和write
            int sockfd=accept(_listensockfd, CONV(peer), &len);
            if (sockfd < 0)
            {
                LOG(LogLevel::WARNING) << "accept error";
                continue;
            }
            InetAddr addr(peer);

            //version3——多线程
            ThreadData *td = new ThreadData(sockfd, addr, this);
            pthread_t tid;
            pthread_create(&tid, nullptr, Routine, td);
            //version1——单进程，一般不会采用
            //service(sockfd,addr);

            //version2
            //多进程
            // pid_t id=fork();
            // if(id<0)
            // {
            //     LOG(LogLevel::FATAL)<<"创建子进程失败";
            //     exit(FORK_ERR);
            // }
            // else if(id==0)//子进程
            // {
            //     //关掉不用的文件描述符
            //     close(_listensockfd);
            //     if(fork()>0)//再次创建子进程
            //     exit(OK);//正常退出

            //     //执行service
            //     service(sockfd,addr);//孙子进程执行
            //     exit(OK);
            // }
            // else
            // {
            //     //父进程
            //     //关掉不用的文件描述符
            //     close(sockfd);
            //     //忽略子进程的退出信号
            //     //signal(SIGCHLD,SIG_IGN);

            //     //父进程直接退出
            //     pid_t rid=waitpid(id,nullptr,0);//父进程不会再等待了
            //     //再次循环执行获取连接的方法 accept
            // }
        }
        _isrunning=false;
    }
private:
    uint16_t _port;
    int _listensockfd;
    bool _isrunning;
    //设置回调处理
    func_t _func;
};